export {};

//  ts永远从安全性考虑

//--------基本类型与字面量类型 的联合类型 -需要包含所有类型 额外属性无法赋值已知属性 a满足ab 少给多-----

let n1!: string | number;

let n2!: string | number | boolean;

// n1 = n2  error  不能将boolean
n2 = n1;

// ----------interface--只考虑自身是否满足自身条件 不考虑额外属性 ab满足a  多给少 ----
interface IA {
  color: string;
}
interface IB {
  color: string;
  age: number;
}
let a1!: IA;
let a2!: IB;
//  a2 = a1  error  a1中缺少age属性
a1 = a2;

//  函数的兼容性（参数,返回值，相当于基本类型）  必须满足自身所有a 满足ab  少给多
let fn1!: (a: string) => string;
let fn2!: (a: string, b: string) => string;
//  fn1 = fn2 error
fn2 = fn1;

let fn3!: (a: string) => string;
let fn4!: (a: string) => string | number;
// fn3 = fn4 error  number类型时不安全
fn4 = fn3;

// 类的兼容性  鸭子类型检测： 只要长的一样就可以兼容
// 不同时 参数使用联合判断 少给多
// 包含 private   protect等关键字时 不能赋值
class Person {
  public readonly name!: string;
}
class Animal {
  public readonly name!: string | number;
}
let person = new Person();
let animal = new Animal();
// person = animal;  error 不能将string|number分配给 string
animal = person;

//  枚举类型 之间互不兼容
enum A {
  age,
}
enum B {
  age,
}
// let e1!: A;
// let e2!: B;
// e1 = e2 error
// e2 = e1 error

//  父子之间的兼容性

class Parent {
  public money!: number;
}

class Son extends Parent {
  public car!: number;
}

class GrandSon extends Son {
  public play!: number;
}

function fn(cb: (val: Son) => Son) {}
//此时父类 money   此时子类  money car  此时孙类   money car paly

let p = new Parent();
p.money;
let s = new Son();
s.money;
s.car;
let g = new GrandSon();
g.car;
g.money;
g.play;
//  传父 参数是逆变的 可以传递父亲给子类  少给多
fn((val: Parent) => {
  return new Son();
});
fn((val: Son) => {
  return new Son();
});
// fn((val: GrandSon) =>{
//   return  new Son()
// } ); // error

//  返子 返回值是协变的 可以返回子类给父亲  多给少
// fn((val: Son) => {
//   return new Parent(); // error
// });
fn((val: Son) => {
  return new Son();
});
fn((val: Son) => {
  return new GrandSon();
});

// 关闭ts配置 strictFunctionTypes时 参数是双向协变的 可以传递子类和父类

fn((val: Parent) => {
  return new Son(); // error
});
fn((val: Son) => {
  return new Son();
});
fn((val: GrandSon) => {
  return new Son();
});

function fn5(cb: (val: string | number) => string | number) {
  // 此时cb算调用  少给多  传父返子 少多 多少
}

fn5((val: string | number | null) => "va");
